
#ifndef __gui_formH__
#define __gui_formH__

#include "gui_layout.h"

namespace WtfGui { namespace Forms {
	/**
	 * Advanced button class, allows registering of many event callbacks, can
	 * accept any widget(s) as the "caption" of the button.
	 **/
	class Button: public LayoutContainer {
		WtfEngine::Functor::tRef	mrOnMouseDown;
		WtfEngine::Functor::tRef	mrOnPress;
		WtfEngine::Functor::tRef	mrOnRightClick;
		WtfEngine::Functor::tRef	mrOnMouseOver;
		WtfEngine::Functor::tRef	mrOnMouseOut;

		public:
			Button(const tCreationOptions& opts, int axis = HORIZONTAL);

			bool OnKeyPress(int key, int flags);
			bool OnMouseDown(const iVector2D& vPos, WtfEngine::tMouseButton btn);
			bool OnMouseUp(const iVector2D& vPos, WtfEngine::tMouseButton btn);
			bool OnMouseOver(const iVector2D& vPos, const iVector2D& vDelta);
			bool OnMouseOut(const iVector2D& vPos, const iVector2D& vDelta);

			const WtfEngine::Functor::tRef& getOnPress() const {
				return mrOnPress;
			};
			void setOnPress(const WtfEngine::Functor::tRef& r) {
				mrOnPress = r;
			};

			const WtfEngine::Functor::tRef& getOnMouseDown() const {
				return mrOnPress;
			};
			void setOnMouseDown(const WtfEngine::Functor::tRef& r) {
				mrOnPress = r;
			};

			const WtfEngine::Functor::tRef& getOnRightClick() const {
				return mrOnRightClick;
			};
			void setOnRightClick(const WtfEngine::Functor::tRef& r) {
				mrOnRightClick = r;
			};

			const WtfEngine::Functor::tRef& getOnMouseOver() const {
				return mrOnMouseOver;
			};
			void setOnMouseOver(const WtfEngine::Functor::tRef& r) {
				mrOnMouseOver = r;
			};

			const WtfEngine::Functor::tRef& getOnMouseOut() const {
				return mrOnMouseOut;
			};
			void setOnMouseOut(const WtfEngine::Functor::tRef& r) {
				mrOnMouseOut = r;
			};

		GC_AUTOSIZE(Button);
	};


	/**
	 * A widget with a draggable slider, for selecting a value from a range.
	 **/
	class Slider: public WidgetContainer, public virtual WtfEngine::IObservable {
		Button::tRef mrMinusButton;
		Button::tRef mrPlusButton;
		Button::tRef mrSlider;

		float mfMin, mfMax, mfValue, mfSnap;
		int miAxis;
		bool mbIsSliding;

	public:
		Slider(int axis, float fMin, float fMax, float fValue, float fSnap = 0.0);

		void UpdateLayout();
		void UpdateValue();

		bool OnMouseDown(const iVector2D& vPos, WtfEngine::tMouseButton btn);
		bool OnMouseUp(const iVector2D& vPos, WtfEngine::tMouseButton btn);
		bool OnMouseMove(const iVector2D& vPos, const iVector2D& vDelta);

		void OnMinusDown();
		void OnPlusDown();
		void OnSliderDown();

		float getMin() const {
			return mfMin;
		};
		void setMin(float f) {
			mfMin = f;
			UpdateLayout();
		};
		float getMax() const {
			return mfMax;
		};
		void setMax(float f) {
			mfMax = f;
			UpdateLayout();
		};

		float getValue() const {
			return mfValue;
		};
		void setValue(float f);

		float getSnap() const {
			return mfSnap;
		};
		void setSnap(float f) {
			mfSnap = f;
			UpdateLayout();
		};

		GC_AUTOSIZE(Slider);
	};

	class Table: public ScrollLayout {
	public:
		/**
		 * Represents a record (can be row or column) in the table. It
		 * retrieves field size values from the parent table when positioning
		 * child widgets.
		 **/
		class Record: public LayoutContainer {
			WtfEngine::WeakRef<Table const> mrTable;

		public:
			Record(const tCreationOptions& opts, int axis, const Table*);

			/// Positions child elements
			void UpdateLayout();

			virtual void AddChild(const Widget::tRef& rChild);
			virtual void RemoveChild(const Widget::tRef& rChild);

			virtual void OnResize();
			virtual void OnChildResize();
			virtual void OnParentResize();

			GC_OBJECT(Record, GC_ADDEDSIZE_AUTO(WidgetContainer, Record));
		};

		/**
		 * Stores the required width for a column (or height for row), and a heading
		 * widget displayed at the top of the table.
		 **/
		struct Heading {
			float        fScale;
			Widget::tRef rBaseWidget;

			Heading(float scale, const Widget::tRef& rBase): fScale(scale), rBaseWidget(rBase) {
			};
		};

	protected:
		Record::tRef         mrHeader;
		std::vector<Heading> mvHeadings;

	public:
		Table(const tCreationOptions& opts, int axis = VERTICAL);

		void AddHeading(const Heading& heading);
		WidgetContainer::tRef AddRecord();

		inline int getNumHeadings() const {
			return mvHeadings.size();
		};
		inline const Heading& getHeading(int i) const {
			return mvHeadings[i];
		};
		void setHeading(int i, const Heading& heading);
	};
}};

#endif
